package com.lingyue.entity.module.es.template;

import groovy.util.logging.Slf4j;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.RequestOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.DefaultResultMapper;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ResultsMapper;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author: Zhiyuan
 * @datetime: 2020/3/24 10:49
 * @version: 1.0.0
 * @Description: TODO
 */
@Slf4j
@Component
public class CustomizedElasticsearchRestTemplate {

    private ResultsMapper resultsMapper;

    public CustomizedElasticsearchRestTemplate() {
        resultsMapper = new DefaultResultMapper(new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()).getMappingContext());
    }

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 获取index name
     *
     * @param aClass
     * @return
     */
    public String getIndexName(Class<?> aClass) {
        return elasticsearchRestTemplate.getPersistentEntityFor(aClass).getIndexName();
    }

    /**
     * 获取index type
     *
     * @param aClass
     * @return
     */
    public String getIndexType(Class<?> aClass) {
        return elasticsearchRestTemplate.getPersistentEntityFor(aClass).getIndexType();
    }

    /**
     * 获取主键
     *
     * @param entity
     * @return
     */
    public String getPersistentEntityId(Object entity) {
        ElasticsearchPersistentEntity<?> persistentEntity = elasticsearchRestTemplate.getPersistentEntityFor(entity.getClass());
        Object identifier = persistentEntity.getIdentifierAccessor(entity).getIdentifier();

        if (identifier != null) {
            return identifier.toString();
        }
        return null;
    }

    /**
     * 实体转IndexQuery
     *
     * @param t
     * @param <T>
     * @return
     */
    public <T> IndexQuery prepareIndex(T t) {
        IndexQuery indexQuery = new IndexQuery();

        String indexName = this.getIndexName(t.getClass());
        if (StringUtils.isEmpty(indexName)) {
            throw new ElasticsearchException("index name is empty");
        }
        indexQuery.setIndexName(indexName);

        String id = this.getPersistentEntityId(t);
        if (StringUtils.isEmpty(id)) {
            throw new ElasticsearchException("object.id is empty");
        }
        indexQuery.setId(this.getPersistentEntityId(t));

        indexQuery.setObject(t);

        return indexQuery;
    }

    /**
     * 获取 ElasticsearchRestTemplate
     *
     * @return
     */
    public ElasticsearchRestTemplate template() {
        return elasticsearchRestTemplate;
    }

    /**
     * 新增document
     */
    public <T> void save(T t, String routing) {
        if (null == t) {
            throw new ElasticsearchException("object is empty");
        }
        IndexQuery indexQuery = this.prepareIndex(t);
        elasticsearchRestTemplate.bulkIndex(Collections.singletonList(indexQuery), BulkOptions.builder().withRoutingId(routing).build());
    }

    /**
     * 新增document List
     */
    public <T> void saveAll(List<T> tList, String routing) {
        if (tList.isEmpty()) {
            throw new ElasticsearchException("object list is empty");
        }
        List<IndexQuery> indexQueries = new ArrayList<>(tList.size());
        for (T t : tList) {
            IndexQuery indexQuery = this.prepareIndex(t);
            indexQueries.add(indexQuery);
        }
        elasticsearchRestTemplate.bulkIndex(indexQueries, BulkOptions.builder().withRoutingId(routing).build());
    }

    /**
     * 获取数据使用主键
     *
     * @param id
     * @param routing
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> T findById(String id, String routing, Class<T> tClass) {
        ElasticsearchPersistentEntity<T> persistentEntity = elasticsearchRestTemplate.getPersistentEntityFor(tClass);
        GetRequest getRequest = new GetRequest(persistentEntity.getIndexName(), persistentEntity.getIndexType(),
                id);
        getRequest.routing(routing);
        GetResponse response;
        try {
            response = elasticsearchRestTemplate.getClient().get(getRequest, RequestOptions.DEFAULT);
            return resultsMapper.mapResult(response, tClass);
        } catch (IOException e) {
            throw new ElasticsearchException("Error while getting for request: " + getRequest.toString(), e);
        }
    }

}
